package estadistica;


/**
 * El sistema es de varios canales con capacidad infinita
 * y poblacion infinita sin rechazo.
 * 
 * 
 * lambda = Numero promedio de clientes que arriban 
 * 			al sistema por unidad de tiempo 
 * 			(tasa promedio de arribos)
 * 
 * Ta = Intervalo promedio entre arribos de clientes 
 * 		(tiempo promedio de arribos) = 1/lambda
 * 
 * mu = Numero promedio de clientes que puede atender 
 * 		un canal por unidad de tiempo 
 * 		(velocidad promedio de atencion)
 * 
 * Ts = Duracion promedio del servicio 
 * 		(o tiempo promedio de atencion) = 1/mu
 * 
 * rho = Factor de transito (o de trafico) = lambda/mu
 * 
 * n = Estado del sistema (es la cantidad de clientes que hay
 * 	   dentro del sistema en un momento determinado)
 * 
 * Pn = Probabilidad de que el sistema 
 * 		  se encuentre en el estado "n"
 * 
 * M = Cantidad de canales dispuestos en paralelo en la unidad 
 * 	   operativa de atencion
 * 
 * H = Numero promedio de canales activos 
 * 	 = rho
 * 
 * Lc = Longitud promedio de la cola (numero esperado de clientes
 * 		esperando ser atendidos) 

 * 
 * L = Longitud promedio del sistema (numero esperado de clientes
 * 	   dentro del sistema)
 * 	   = Sumatoria desde 0 hasta N de "n por p(n)"
 * 	   = Lc + H
 * 
 * 
 * lambdaRaya = Tasa promedio de ingreso de clientes al sistema
 * 				= Sumatoria desde 0 a N de (lambdaN * p(n))
 * 
 * muRaya = Tasa promedio de egreso del sistema de clientes
 * 			que recibieron el servicio
 * 			= Sumatoria desde 0 a N de (muN * p(n))
 * 			= mu * H
 * 
 *  PA = Porcentaje de actividad del canal
 *  	 = H/M
 *  	 = rho/M
 *  
 *  Wc = Tiempo promedio de espera en cola de un cliente
 *  	= Lc/lambdaRaya
 *  
 *  W = Tiempo promedio de permanencia en el sistema de un cliente
 *  	= Wc + Ts
 *  	= L/lambdaRaya
 * 
 * */

public class QueueFunction {

	private double lambda;
	private double Ta;
	private double mu;
	private double Ts;
	private double rho;
	private int n;
	private int M;
	private double H;
	private double Lc;
	private double L;
	private double lambdaRaya;
	private double muRaya;
	private double PA;
	private double Wc;
	private double W;
	private double Pn;
	private double Pcero;
	
	public static void main(String p[]) throws Exception {
		QueueFunction qf = new QueueFunction(50, 40, 1, 200);
		qf.getLc();
	}
	
	public QueueFunction(double lambda, double mu, int M, int n ) throws Exception {
		setLambda(lambda);
		setMu(mu);
		setM(M);
		setRho();
		
		if(this.getRho() >= this.getM()) 
			throw new Exception("Rho es menor a M");
	
		setTa();
		setTs();
		setLambdaRaya();
		setH();
		setMuRaya();
		setPA();
		setn(n);
		setPcero();
		setPn();
		setLc();
		setL();
		setWc();
		setW();
	}

	private long factorial(int x)
	{
	    long i,f;
	    i=0;
	    f=1;
	    while (i != x)
	        {
	        i=i+1;
	        f=f*i;
	        }
	    return f;
	}

	public double getPcero() {
		return Pcero;
	}

	private void setPcero() {
		double sumatoria =0; 
		double rhoALaN;
		double factorialDeN;
		double rhoALaM;
		double factorialDeMMenos1;
		double factorialPorMMenosRho;
		double suma1;
		double suma2;
		
		rhoALaM = (Math.pow(rho, M));
		factorialDeMMenos1 = factorial(M-1);
		factorialPorMMenosRho = factorialDeMMenos1 * (M - rho);
		suma2 = rhoALaM / factorialPorMMenosRho;
		
		for(int i = 0; i<= M-1; i++ ){
			rhoALaN = (Math.pow(rho, i));
			factorialDeN = factorial(i);
			suma1 = rhoALaN / factorialDeN;
			sumatoria = sumatoria + (suma1+suma2);
		}
		Pcero = 1/sumatoria;
	}
	
	public double getPn() {
		return Pn;
	}

	private void setPn() {
		if (n < M){
			double rhoALaN = (Math.pow(rho, n));
			double factorialDeN = factorial(n);
			Pn = Pcero * (rhoALaN/factorialDeN);
		}else{
			double rhoDivididoMALaN = (Math.pow(rho/M, n));
			double factorialDeM = factorial(M);
			double mALaM = (Math.pow(M, M));
			Pn = Pcero * (rhoDivididoMALaN * (mALaM/factorialDeM));
			
		}
	}
	
	public double getLambda() {
		return lambda;
	}

	private void setLambda(double lambda) {
		this.lambda = lambda;
	}

	public double getTa() {
		return Ta;
	}

	private void setTa() {
		Ta = 1/this.lambda;
	}

	public double getMu() {
		return mu;
	}

	private void setMu(double mu) {
		this.mu = mu;
	}

	public double getTs() {
		return Ts;
	}

	private void setTs() {
		Ts = 1/this.mu;
	}

	public double getRho() {
		return rho;
	}

	private void setRho() {
		this.rho = this.lambda/this.mu;
	}

	public double getn() {
		return n;
	}

	private void setn(int n) {
		this.n = n;
	}

	public double getM() {
		return M;
	}

	private void setM(int m) {
		M = m;
	}

	public double getH() {
		return H;
	}

	private void setH() {
		H = this.rho;
	}

	public double getLc() {
		return Lc;
	}

	private void setLc() {
		double nominador = lambda * mu * (Math.pow(rho, M));
		double MPorMuMenosLambda= (M*mu) - lambda;
		double denominador = factorial(M - 1) * (Math.pow(MPorMuMenosLambda, 2));
		Lc = Pcero * (nominador / denominador);
	}

	public double getL() {
		return L;
	}

	private void setL() {
		this.L = this.Lc + this.H;
	}

	public double getLambdaRaya() {
		return lambdaRaya;
	}

	private void setLambdaRaya() {
		//porque no hay rechazo
		this.lambdaRaya = lambda;
	}

	public double getMuRaya() {
		return muRaya;
	}

	private void setMuRaya() {
		this.muRaya = this.mu * this.H;
	}

	public double getPA() {
		return PA;
	}

	private void setPA() {
		this.PA = this.H/this.M;
	}

	public double getWc() {
		return Wc;
	}

	private void setWc() {
		this.Wc = this.Lc/this.lambdaRaya;
	}

	public double getW() {
		return W;
	}

	private void setW() {
		this.W = this.L/this.lambdaRaya;
	}

}

